package com.hzc.springchan.service;

import com.hzc.springchan.bean.exception.CException;
import com.hzc.springchan.bean.request.Request;
import com.hzc.springchan.enums.ICodeBusiness;
import com.hzc.springchan.enums.PrivError;
import com.hzc.springchan.util.LogUtils;
import com.hzc.springchan.util.RandUtils;
import com.hzc.springchan.util.RedisUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang.StringUtils;

/**
 * 验证码服务接口
 * @author chen990627
 * @date 2022/10/16
 */
public interface IVerifyCodeService {

    Integer DEFAULT_CODE_LEN = 6;

    /**
     * 发送验证码：业务使用
     *
     * @param request
     * @return
     */
    default VerifyResponse sendCode(Request request) {
        sendCodeDoParamCheck(request);
        VerifyRequest verifyRequest = new VerifyRequest(request);
        RedisUtils.setString(redisKey(verifyRequest), verifyRequest.getVerifyCode(), 1800);

        return doSendCode(verifyRequest);
    }

    /**
     * 发送验证码参数校验：核心重写
     *
     * @param request
     */
    default void sendCodeDoParamCheck(Request request) {
        paramCheck(request);
    }

    /**
     * 发送验证码：核心重写
     *
     * @param request
     */
    VerifyResponse doSendCode(VerifyRequest request);

    /**
     * 验证码校验：业务使用
     *
     * @param request
     * @return
     */
    default VerifyResponse verifyCode(Request request) {
        verifyCodeDoParamCheck(request);
        return doVerifyCode(new VerifyRequest(request));
    }

    /**
     * 删除验证码：业务使用
     *
     * @param request
     */
    default void deleteCode(Request request) {
        RedisUtils.delString(redisKey(new VerifyRequest(request)));
    }

    /**
     * 验证码校验参数校验：核心重写
     *
     * @param request
     */
    default void verifyCodeDoParamCheck(Request request) {
        paramCheck(request);
    }

    /**
     * 验证码校验：核心重写
     *
     * @param request
     * @return
     */
    default VerifyResponse doVerifyCode(VerifyRequest request) {

        String redisKey = redisKey(request);
        String realCode = RedisUtils.getString(redisKey);
        LogUtils.info(this, "realCode = {}, verifyCode = {}", realCode, request.getVerifyCode());

        if (StringUtils.isEmpty(realCode)) {
            return VerifyResponse.codeExpire();
        }

        if (!realCode.equals(request.getVerifyCode())) {
            return VerifyResponse.codeError();
        }
        return VerifyResponse.success();
    }

    default void paramCheck(Request request) {

        Object receiver = request.get("receiver");
        Object verifyCode = request.get("verifyCode");
        Object business = request.get("business");

        if (receiver == null || verifyCode == null || business == null) {
            throw new CException(PrivError.CPARAM_CHECK_FAILED);
        }

        if (!(receiver instanceof String) || !(verifyCode instanceof String) || !(business instanceof ICodeBusiness)) {
            throw new CException(PrivError.CPARAM_CHECK_FAILED);
        }

        if (StringUtils.isEmpty((String) receiver)) {
            throw new CException(PrivError.CPARAM_CHECK_FAILED);
        }
    }

    /**
     * redis缓存key
     *
     * @param request
     * @return
     */
    String redisKey(VerifyRequest request);

    /**
     * 6位验证码生成
     *
     * @return
     */
    default String generateCode() {
        return RandUtils.randStr(DEFAULT_CODE_LEN, true);
    }

    @Data
    class VerifyRequest {

        /**
         * 业务类型
         */
        ICodeBusiness business;

        /**
         * 验证码接收者
         */
        String receiver;

        /**
         * 验证码
         */
        String verifyCode;

        public VerifyRequest(Request request) {

            this.receiver = (String) request.get("receiver");
            this.verifyCode = (String) request.get("verifyCode");
            this.business = (ICodeBusiness) request.get("business");
        }
    }

    @Data
    @AllArgsConstructor
    class VerifyResponse {

        /**
         * 校验成功
         */
        final static int SUCCESS = 0;
        /**
         * 验证码错误
         */
        final static int CODE_ERROR = 101;
        /**
         * 验证码已失效
         */
        final static int CODE_EXPIRE = 102;
        /**
         * 验证码发送失败
         */
        final static int SEND_ERROR = 103;

        int resultCode;

        public static VerifyResponse success() {
            return new VerifyResponse(SUCCESS);
        }

        public static VerifyResponse codeError() {
            return new VerifyResponse(CODE_ERROR);
        }

        public static VerifyResponse codeExpire() {
            return new VerifyResponse(CODE_EXPIRE);
        }

        public static VerifyResponse sendError() {
            return new VerifyResponse(SEND_ERROR);
        }

        public boolean isSuccess() {
            return this.resultCode == SUCCESS;
        }

        public boolean isCodeError() {
            return this.resultCode == CODE_ERROR;
        }

        public boolean isCodeExpire() {
            return this.resultCode == CODE_EXPIRE;
        }

        public boolean isSendError() {
            return this.resultCode == SEND_ERROR;
        }
    }
}
